iT邦幫忙

2026 iThome 鐵人賽

DAY 4
0
Claude AI

Claude Code陪跑:一人開發者的訂閱制SaaS架構與十大地雷實戰記系列 第 4

# Day 4|地雷#1:SQL 字面 `%` 吃掉正式站,本機環境全綠的假象

  • 分享至 

  • xImage
  •  

事故現場

某天正式站一個查詢功能整天回 500。本機重現:完全正常。測試:全綠。程式碼 diff 看了三遍:沒有任何可疑之處。這種「本機好好的、正式站死了」的事故,是雙資料庫架構(Day 2)欠的債找上門了。

根因解剖

正式站的 Python 驅動程式(psycopg2 這一系)的參數化查詢,用的佔位符語法是 %s

cur.execute("SELECT * FROM items WHERE id = %s", (item_id,))

驅動程式在送出 SQL 前會解析字串裡所有的 %。問題來了:如果你的 SQL 本身含有字面上的 %——最常見的兩個場景:

# 模糊搜尋
cur.execute("SELECT * FROM items WHERE name LIKE '%關鍵字%' AND type = %s", (t,))

# 日期格式化
cur.execute("SELECT strftime('%Y-%m', created_at), COUNT(*) FROM logs WHERE user = %s", (u,))

驅動程式會試圖把 '%關''%Y' 也解析成佔位符,解析失敗,整條查詢炸掉。

而本機的 DuckDB 用的是 ? 佔位符,字面 % 對它毫無意義,所以本機測試永遠是綠的。這條地雷的殺傷力就在這裡:你所有的安全網(本機測試、CI)都偵測不到它,第一個發現的人是正式站的使用者。

防線怎麼蓋

治本的做法是在連線層加一道轉換(db.py 裡的 SQL 轉換函式),把要送去正式站的 SQL 統一處理:字面 % 轉義成 %%? 佔位符轉成 %s。所有 SQL 都走這一層,個別開發者(跟 AI agent)不需要記得手動轉義。

但光有防線不夠,這條雷的教訓有三層:

第一層:技術教訓。 含字面 % 又帶參數的 SQL 是高危組合,寫的當下就要意識到。

第二層:流程教訓。 「本機全綠」在雙資料庫架構下不是安全證明,只是「本機方言下正確」的證明。部署後的健康檢查(Day 27)因此變成必要而不是加分項。

第三層:協作教訓。 這條進了 CLAUDE.md 地雷清單之後,agent 每次寫到 LIKE 或日期格式化都會主動確認轉義——這正是 Day 3 說的「把肌肉記憶外部化」的實例。

番外:同一條雷炸兩次

這條雷後來在另一個完全不相關的功能裡復發過——同樣是字面 %,另一段被複製貼上過的程式碼。當下的體會變成另一條通則寫進了文件:複製貼上型的 bug 一定成對出現,查到一處,必須順手搜一次整個專案還有沒有同樣形狀的地方。 這件事交給 agent 做特別合適:「找出專案裡所有含字面 % 且帶參數的 SQL」是一句話的事。


上一篇
# Day 3|CLAUDE.md 是什麼?把地雷清單寫給 AI 讀,不是寫給自己看
系列文
Claude Code陪跑:一人開發者的訂閱制SaaS架構與十大地雷實戰記4
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言